package com.example.lotterysystem.service.impl;

import com.example.lotterysystem.common.config.DirectRabbitConfig;
import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.utils.JacksonUtil;
import com.example.lotterysystem.common.utils.RedisUtil;
import com.example.lotterysystem.controller.param.DrawPrizeParam;
import com.example.lotterysystem.controller.param.WinningRecordsParam;
import com.example.lotterysystem.dao.dataobject.*;
import com.example.lotterysystem.dao.mapper.*;
import com.example.lotterysystem.service.IDrawPrizeService;
import com.example.lotterysystem.service.dto.WinningRecordDTO;
import com.example.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.example.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.example.lotterysystem.service.enums.ActivityStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能描述:
 *
 * @author Lenovo
 * @date 2025/2/2
 */
@Slf4j
@Service
public class DrawPrizeServiceImpl implements IDrawPrizeService {

    private final String WINNING_RECORDS_PREFIX = "WINNING_RECORDS_";
    private final Long WINNING_RECORDS_TIMEOUT = 60 * 60 * 24 * 2L;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PrizeMapper prizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public void drawPrize(DrawPrizeParam param) {
        Map<String, String> map = new HashMap<>();
        map.put("messageId", String.valueOf(UUID.randomUUID()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));
        //加入消息队列
        rabbitTemplate.convertAndSend(DirectRabbitConfig.EXCHANGE_NAME,
                DirectRabbitConfig.ROUTING, map);
        log.info("消息发送成功：map={}", JacksonUtil.writeValueAsString(map));
    }

    @Override
    public boolean checkDrawPrizeParam(DrawPrizeParam param) {
        //活动是否有效
        ActivityDO activityDO = activityMapper.selectActivityById(param.getActivityId());

        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectPrizeByAPId(
                param.getActivityId(), param.getPrizeId()
        );
        if (activityDO == null || activityPrizeDO == null) {
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
            log.info("校验抽奖请求失败：{}", ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_IS_EMPTY);
            return false;
        }
        if (ActivityStatusEnum.COMPLETED.name().equals(activityDO.getStatus())) {
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_COMPLETED);
            log.info("校验抽奖请求失败：{}", ServiceErrorCodeConstants.ACTIVITY_COMPLETED);
            return false;
        }
        //奖品是否有效
        if (ActivityPrizeStatusEnum.COMPLETED.name().equals(activityPrizeDO.getStatus())) {
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED);
            log.info("校验抽奖请求失败：{}", ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED);
            return false;
        }
        //校验中奖人数
        if (activityPrizeDO.getPrizeAmount() != param.getWinnerList().size()) {
            //throw new ServiceException(ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR);
            log.info("校验抽奖请求失败：{}", ServiceErrorCodeConstants.WINNER_PRIZE_AMOUNT_ERROR);
            return false;
        }
        return true;
    }

    @Override
    public List<WinningRecordDO> saveWinnerRecords(DrawPrizeParam param) {
        //查询相关信息
        ActivityDO activityDO = activityMapper.selectActivityById(param.getActivityId());
        List<UserDO> userDOList = userMapper.batchSelectByIds(param.getWinnerList()
                .stream()
                .map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList())
        );
        PrizeDO prizeDO = prizeMapper.selectById(param.getPrizeId());
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper
                .selectPrizeByAPId(param.getActivityId(), param.getPrizeId());

        //构造中奖记录
        List<WinningRecordDO> winningRecordDOS = userDOList
                .stream()
                .map(userDO -> {
                    WinningRecordDO winningRecordDO = new WinningRecordDO();
                    winningRecordDO.setActivityId(activityDO.getId());
                    winningRecordDO.setActivityName(activityDO.getActivityName());
                    winningRecordDO.setPrizeId(prizeDO.getId());
                    winningRecordDO.setPrizeName(prizeDO.getName());
                    winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
                    winningRecordDO.setWinnerId(userDO.getId());
                    winningRecordDO.setWinnerName(userDO.getUserName());
                    winningRecordDO.setWinnerEmail(userDO.getEmail());
                    winningRecordDO.setWinnerPhoneNumber(userDO.getPhoneNumber());
                    winningRecordDO.setWinningTime(param.getWinningTime());

                    return winningRecordDO;
                }).collect(Collectors.toList());
        winningRecordMapper.batchInsert(winningRecordDOS);
        //缓存中奖记录
        //奖品维度中奖记录
        cacheWinningRecords(param.getActivityId() + "_" + param.getPrizeId(),
                winningRecordDOS, WINNING_RECORDS_TIMEOUT);
        //活动维度中奖记录（活动完成之后存储）
        if (activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())) {
            //查询活动维度全量中奖记录
            List<WinningRecordDO> allList = winningRecordMapper.
                    selectByActivityId(param.getActivityId());
            cacheWinningRecords(String.valueOf(param.getActivityId()),
                    allList,
                    WINNING_RECORDS_TIMEOUT);
        }
        return winningRecordDOS;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if (activityId == null) {
            log.warn("要删除中奖记录相关的activityId为空");
            return;
        }
        //删除数据表
        winningRecordMapper.deleteRecords(activityId, prizeId);
        //删除缓存
        if (prizeId != null) {
            deleteWinningRecords(activityId + "_" + prizeId);
        }
        deleteWinningRecords(String.valueOf(activityId));
    }

    @Override
    public List<WinningRecordDTO> getRecords(WinningRecordsParam param) {
        //查询Redis
        String key = (param.getPrizeId() == null ? String.valueOf(param.getActivityId())
                : param.getActivityId() + "_" + param.getPrizeId());
        List<WinningRecordDO> winningRecords = getWinningRecords(key);
        //查询数据库
        if (CollectionUtils.isEmpty(winningRecords)) {
            winningRecords = winningRecordMapper.selectByActivityIdOrPrizeId(param.getActivityId(), param.getPrizeId());
        }
        if (CollectionUtils.isEmpty(winningRecords)) {
            return new ArrayList<>();
        }
        //存储Redis
        cacheWinningRecords(key, winningRecords, WINNING_RECORDS_TIMEOUT);
        return convertToWinningRecordDTOList(winningRecords);
    }

    private List<WinningRecordDTO> convertToWinningRecordDTOList(List<WinningRecordDO> winningRecords) {
        if (CollectionUtils.isEmpty(winningRecords)) {
            return new ArrayList<>();
        }
        return winningRecords.stream().map(winningRecordDO -> {
            WinningRecordDTO winningRecordDTO = new WinningRecordDTO();
            winningRecordDTO.setWinnerId(winningRecordDO.getWinnerId());
            winningRecordDTO.setWinnerName(winningRecordDO.getWinnerName());
            winningRecordDTO.setPrizeName(winningRecordDO.getPrizeName());
            winningRecordDTO.setPrizeTier(ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()));
            winningRecordDTO.setWinningTime(winningRecordDO.getWinningTime());
            return winningRecordDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 删除缓存中的中奖记录
     *
     * @param key
     */
    private void deleteWinningRecords(String key) {
        try {
            if (redisUtil.hasKey(WINNING_RECORDS_PREFIX + key)) {
                redisUtil.delete(WINNING_RECORDS_PREFIX + key);
            }
        } catch (Exception e) {
            log.error("删除缓存中奖记录异常，key：{}", key);
        }
    }

    /**
     * 缓存中奖记录
     *
     * @param key
     * @param winningRecordDOS
     * @param time
     */
    private void cacheWinningRecords(String key,
                                     List<WinningRecordDO> winningRecordDOS, Long time) {
        String str = "";
        try {
            str = JacksonUtil.writeValueAsString(winningRecordDOS);
            if (!StringUtils.hasText(key) || CollectionUtils.isEmpty(winningRecordDOS)) {
                log.warn("要缓存的内容为空，key:{},value:{}", key, str);
                return;
            }
            redisUtil.set(WINNING_RECORDS_PREFIX + key,
                    str,
                    time);
        } catch (Exception e) {
            log.error("缓存中间记录异常，key:{},value:{}", WINNING_RECORDS_PREFIX + key, str);
        }

    }


    private List<WinningRecordDO> getWinningRecords(String key) {
        try {
            String str = redisUtil.get(WINNING_RECORDS_PREFIX + key);
            if (!StringUtils.hasText(key) || !StringUtils.hasText(str)) {
                return new ArrayList<>();
            }
            List<WinningRecordDO> winningRecordDOS =
                    JacksonUtil.readListValue(str, WinningRecordDO.class);
            return winningRecordDOS;
        } catch (Exception e) {
            log.error("从缓存中查询中奖记录异常：key:{}", WINNING_RECORDS_PREFIX + key);
            return new ArrayList<>();
        }
    }
}
